home *** CD-ROM | disk | FTP | other *** search
/ Eagles Nest BBS 7 / Eagles_Nest_Mac_Collection_Disc_7.TOAST / General Communication / Y&ZmodemC / rz.c < prev    next >
C/C++ Source or Header  |  1989-01-10  |  31KB  |  1,504 lines

  1. #define VERSION "2.03 05-17-88"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*% cc -compat -M2 -Ox -K -i -DMD -DOMEN % -o rz; size rz;
  5. <-xtx-*> cc386 -Ox -DMD -DOMEN -DSEGMENTS=8 rz.c -o $B/rz;  size $B/rz
  6.  *
  7.  * rz.c By Chuck Forsberg
  8.  *
  9.  *    cc -O rz.c -o rz        USG (3.0) Unix
  10.  *     cc -O -DV7  rz.c -o rz        Unix V7, BSD 2.8 - 4.3
  11.  *
  12.  *    ln rz rb;  ln rz rx            For either system
  13.  *
  14.  *    ln rz /usr/bin/rzrmail        For remote mail.  Make this the
  15.  *                    login shell. rzrmail then calls
  16.  *                    rmail(1) to deliver mail.
  17.  *
  18.  * To compile on VMS:
  19.  *
  20.  *    define LNK$LIBRARY   SYS$LIBRARY:VAXCRTL.OLB
  21.  *    cc rz.c
  22.  *    cc vvmodem.c
  23.  *    link rz,vvmodem
  24.  *    rz :== $disk:[username.subdir]rz.exe
  25.  *
  26.  *
  27.  *  Unix is a trademark of Western Electric Company
  28.  *
  29.  * A program for Unix to receive files and commands from computers running
  30.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  31.  *  rz uses Unix buffered input to reduce wasted CPU time.
  32.  *
  33.  * Iff the program is invoked by rzCOMMAND, output is piped to 
  34.  * "COMMAND filename"  (Unix only)
  35.  *
  36.  *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
  37.  *  read(2) the same way as Unix. ONEREAD must be defined to force one
  38.  *  character reads for these systems. Added 7-01-84 CAF
  39.  *
  40.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  41.  *
  42.  *  BIX added 6-30-87 to support BIX(TM) upload protocol used by the
  43.  *  Byte Information Exchange.
  44.  *
  45.  *  NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN]
  46.  *  doesn't work properly (even though it compiles without error!),
  47.  *
  48.  *  SEGMENTS=n added 2-21-88 as a model for CP/M programs
  49.  *    for CP/M-80 systems that cannot overlap modem and disk I/O.
  50.  *
  51.  *  VMS flavor hacks begin with rz version 2.00
  52.  *
  53.  *  -DMD may be added to compiler command line to compile in
  54.  *    Directory-creating routines from Public Domain TAR by John Gilmore
  55.  *
  56.  *  HOWMANY may be tuned for best performance
  57.  *
  58.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  59.  */
  60.  
  61. #ifdef vax11c
  62. #include <types.h>
  63. #include <stat.h>
  64. #define LOGFILE "rzlog.tmp"
  65. #include <stdio.h>
  66. #include <signal.h>
  67. #include <setjmp.h>
  68. #include <ctype.h>
  69. #include <errno.h>
  70. #define OS "VMS"
  71. #define BUFREAD
  72. extern int errno;
  73. #define SS_NORMAL SS$_NORMAL
  74. #else
  75. #define SS_NORMAL 0
  76. #define LOGFILE "/tmp/rzlog"
  77. #include <stdio.h>
  78. #include <signal.h>
  79. #include <setjmp.h>
  80. #include <ctype.h>
  81. #include <errno.h>
  82. extern int errno;
  83. FILE *popen();
  84. #endif
  85.  
  86. #define OK 0
  87. #define FALSE 0
  88. #define TRUE 1
  89. #define ERROR (-1)
  90.  
  91. /*
  92.  * Max value for HOWMANY is 255.
  93.  *   A larger value reduces system overhead but may evoke kernel bugs.
  94.  *   133 corresponds to an XMODEM/CRC sector
  95.  */
  96. #ifndef HOWMANY
  97. #define HOWMANY 133
  98. #endif
  99.  
  100. /* Ward Christensen / CP/M parameters - Don't change these! */
  101. #define ENQ 005
  102. #define CAN ('X'&037)
  103. #define XOFF ('s'&037)
  104. #define XON ('q'&037)
  105. #define SOH 1
  106. #define STX 2
  107. #define EOT 4
  108. #define ACK 6
  109. #define NAK 025
  110. #define CPMEOF 032
  111. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  112. #define TIMEOUT (-2)
  113. #define RCDO (-3)
  114. #define ERRORMAX 5
  115. #define RETRYMAX 5
  116. #define WCEOT (-10)
  117. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  118. #define UNIXFILE 0xF000    /* The S_IFMT file mask bit for stat */
  119.  
  120. int Zmodem=0;        /* ZMODEM protocol requested */
  121. int Nozmodem = 0;    /* If invoked as "rb" */
  122. unsigned Baudrate = 2400;
  123. #ifdef vax11c
  124. #include "vrzsz.c"    /* most of the system dependent stuff here */
  125. #else
  126. #include "rbsb.c"    /* most of the system dependent stuff here */
  127. #endif
  128. #include "crctab.c"
  129.  
  130. char *substr();
  131. FILE *fout;
  132.  
  133. /*
  134.  * Routine to calculate the free bytes on the current file system
  135.  *  ~0 means many free bytes (unknown)
  136.  */
  137. long getfree()
  138. {
  139.     return(~0L);    /* many free bytes ... */
  140. }
  141.  
  142. int Lastrx;
  143. int Crcflg;
  144. int Firstsec;
  145. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  146. int errors;
  147. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  148. #ifdef ONEREAD
  149. /* Sorry, Regulus and some others don't work right in raw mode! */
  150. int Readnum = 1;    /* Number of bytes to ask for in read() from modem */
  151. #else
  152. int Readnum = HOWMANY;    /* Number of bytes to ask for in read() from modem */
  153. #endif
  154.  
  155. #define DEFBYTL 2000000000L    /* default rx file size */
  156. long Bytesleft;        /* number of bytes of incoming file left */
  157. long Modtime;        /* Unix style mod time for incoming file */
  158. int Filemode;        /* Unix style mode for incoming file */
  159. char Pathname[PATHLEN];
  160. char *Progname;        /* the name by which we were called */
  161.  
  162. int Batch=0;
  163. int Topipe=0;
  164. int MakeLCPathname=TRUE;    /* make received pathname lower case */
  165. int Verbose=0;
  166. int Quiet=0;        /* overrides logic that would otherwise set verbose */
  167. int Nflag = 0;        /* Don't really transfer files */
  168. int Rxclob=FALSE;    /* Clobber existing file */
  169. int Rxbinary=FALSE;    /* receive all files in bin mode */
  170. int Rxascii=FALSE;    /* receive files in ascii (translate) mode */
  171. int Thisbinary;        /* current file is to be received in bin mode */
  172. int Blklen;        /* record length of received packets */
  173.  
  174. #ifdef SEGMENTS
  175. int chinseg = 0;    /* Number of characters received in this data seg */
  176. char secbuf[1+(SEGMENTS+1)*1024];
  177. #else
  178. char secbuf[1025];
  179. #endif
  180.  
  181.  
  182. char linbuf[HOWMANY];
  183. int Lleft=0;        /* number of characters in linbuf */
  184. time_t timep[2];
  185. char Lzmanag;        /* Local file management request */
  186. char zconv;        /* ZMODEM file conversion request */
  187. char zmanag;        /* ZMODEM file management request */
  188. char ztrans;        /* ZMODEM file transport request */
  189. int Zctlesc;        /* Encode control characters */
  190. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  191.  
  192. jmp_buf tohere;        /* For the interrupt on RX timeout */
  193.  
  194. #define xsendline(c) sendline(c)
  195. #include "zm.c"
  196.  
  197. int tryzhdrtype=ZRINIT;    /* Header type to send corresponding to Last rx close */
  198.  
  199. alrm()
  200. {
  201.     longjmp(tohere, -1);
  202. }
  203.  
  204. /* called by signal interrupt or terminate to clean things up */
  205. bibi(n)
  206. {
  207.     if (Zmodem)
  208.         zmputs(Attn);
  209.     canit(); mode(0);
  210.     fprintf(stderr, "rz: caught signal %d; exiting", n);
  211.     cucheck();
  212.     exit(128+n);
  213. }
  214.  
  215. main(argc, argv)
  216. char *argv[];
  217. {
  218.     register char *cp;
  219.     register npats;
  220.     char *virgin, **patts;
  221.     char *getenv();
  222.     int exitcode;
  223.  
  224.     Rxtimeout = 100;
  225.     setbuf(stderr, NULL);
  226.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  227.         Restricted=TRUE;
  228.  
  229.     from_cu();
  230. #ifdef vax11c
  231.     Progname = virgin = "rz";
  232. #else
  233.     chkinvok(virgin=argv[0]);    /* if called as [-]rzCOMMAND set flag */
  234. #endif
  235.     npats = 0;
  236.     while (--argc) {
  237.         cp = *++argv;
  238.         if (*cp == '-') {
  239.             while( *++cp) {
  240.                 switch(*cp) {
  241.                 case '\\':
  242.                      cp[1] = toupper(cp[1]);  continue;
  243.                 case '+':
  244.                     Lzmanag = ZMAPND; break;
  245.                 case 'a':
  246.                     Rxascii=TRUE;  break;
  247.                 case 'b':
  248.                     Rxbinary=TRUE; break;
  249.                 case 'c':
  250.                     Crcflg=TRUE; break;
  251. #ifndef vax11c
  252.                 case 'D':
  253.                     Nflag = TRUE; break;
  254. #endif
  255.                 case 'e':
  256.                     Zctlesc = 1; break;
  257.                 case 'p':
  258.                     Lzmanag = ZMPROT;  break;
  259.                 case 'q':
  260.                     Quiet=TRUE; Verbose=0; break;
  261.                 case 't':
  262.                     if (--argc < 1) {
  263.                         usage();
  264.                     }
  265.                     Rxtimeout = atoi(*++argv);
  266.                     if (Rxtimeout<10 || Rxtimeout>1000)
  267.                         usage();
  268.                     break;
  269.                 case 'w':
  270.                     if (--argc < 1) {
  271.                         usage();
  272.                     }
  273.                     Zrwindow = atoi(*++argv);
  274.                     break;
  275.                 case 'u':
  276.                     MakeLCPathname=FALSE; break;
  277.                 case 'v':
  278.                     ++Verbose; break;
  279.                 case 'y':
  280.                     Rxclob=TRUE; break;
  281.                 default:
  282.                     usage();
  283.                 }
  284.             }
  285.         }
  286.         else if ( !npats && argc>0) {
  287.             if (argv[0][0]) {
  288.                 npats=argc;
  289.                 patts=argv;
  290.             }
  291.         }
  292.     }
  293.     if (npats > 1)
  294.         usage();
  295.     if (Batch && npats)
  296.         usage();
  297.     if (Verbose) {
  298.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  299.             printf("Can't open log file %s\n",LOGFILE);
  300.             exit(0200);
  301.         }
  302.         setbuf(stderr, NULL);
  303.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  304.     }
  305.     if (Fromcu && !Quiet) {
  306.         if (Verbose == 0)
  307.             Verbose = 2;
  308.     }
  309.     vfile("%s %s for %s\n", Progname, VERSION, OS);
  310.     mode(1);
  311.     if (signal(SIGINT, bibi) == SIG_IGN) {
  312.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  313.     }
  314.     else {
  315.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  316.     }
  317.     signal(SIGTERM, bibi);
  318.     if (wcreceive(npats, patts)==ERROR) {
  319.         exitcode=0200;
  320.         canit();
  321.     }
  322.     mode(0);
  323.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  324.         canit();
  325.     if (exitcode)
  326.         cucheck();
  327.     exit(exitcode ? exitcode:SS_NORMAL);
  328. }
  329.  
  330.  
  331. usage()
  332. {
  333.     cucheck();
  334. #ifdef vax11c
  335.     fprintf(stderr,"Usage:    rz [-abeuvy]\n");
  336. #else
  337.     fprintf(stderr,"Usage:    rz [-abeuvy]        (ZMODEM)\n");
  338.     fprintf(stderr,"or    rb [-abuvy]        (YMODEM)\n");
  339.     fprintf(stderr,"or    rx [-abcv] file    (XMODEM or XMODEM-1k)\n");
  340. #endif
  341.     fprintf(stderr,"      -a ASCII transfer (strip CR)\n");
  342.     fprintf(stderr,"      -b Binary transfer for all files\n");
  343. #ifndef vax11c
  344.     fprintf(stderr,"      -c Use 16 bit CRC    (XMODEM)\n");
  345. #endif
  346.     fprintf(stderr,"      -e Escape control characters    (ZMODEM)\n");
  347.     fprintf(stderr,"      -v Verbose more v's give more info\n");
  348.     fprintf(stderr,"      -y Yes, clobber existing file if any\n");
  349.     fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
  350.       Progname, VERSION, OS);
  351.     fprintf(stderr, "\t\t\042The High Reliability Software\042\n");
  352.     exit(SS_NORMAL);
  353. }
  354. /*
  355.  *  Debugging information output interface routine
  356.  */
  357. /* VARARGS1 */
  358. vfile(f, a, b, c)
  359. register char *f;
  360. {
  361.     if (Verbose > 2) {
  362.         fprintf(stderr, f, a, b, c);
  363.         fprintf(stderr, "\n");
  364.     }
  365. }
  366.  
  367. /*
  368.  * Let's receive something already.
  369.  */
  370.  
  371. char *rbmsg =
  372. "%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n";
  373.  
  374. wcreceive(argc, argp)
  375. char **argp;
  376. {
  377.     register c;
  378.  
  379.     if (Batch || argc==0) {
  380.         Crcflg=1;
  381.         if ( !Quiet)
  382.             fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
  383.         if (c=tryz()) {
  384.             if (c == ZCOMPL)
  385.                 return OK;
  386.             if (c == ERROR)
  387.                 goto fubar;
  388.             c = rzfiles();
  389.             if (c)
  390.                 goto fubar;
  391.         } else {
  392.             for (;;) {
  393.                 if (wcrxpn(secbuf)== ERROR)
  394.                     goto fubar;
  395.                 if (secbuf[0]==0)
  396.                     return OK;
  397.                 if (procheader(secbuf) == ERROR)
  398.                     goto fubar;
  399.                 if (wcrx()==ERROR)
  400.                     goto fubar;
  401.             }
  402.         }
  403.     } else {
  404.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  405.  
  406.         procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
  407.         fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  408.         if ((fout=fopen(Pathname, "w")) == NULL)
  409.             return ERROR;
  410.         if (wcrx()==ERROR)
  411.             goto fubar;
  412.     }
  413.     return OK;
  414. fubar:
  415.     canit();
  416. #ifndef vax11c
  417.     if (Topipe && fout) {
  418.         pclose(fout);  return ERROR;
  419.     }
  420. #endif
  421.     if (fout)
  422.         fclose(fout);
  423. #ifndef vax11c
  424.     if (Restricted) {
  425.         unlink(Pathname);
  426.         fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  427.     }
  428. #endif
  429.     return ERROR;
  430. }
  431.  
  432.  
  433. /*
  434.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  435.  * Length is indeterminate as long as less than Blklen
  436.  * A null string represents no more files (YMODEM)
  437.  */
  438. wcrxpn(rpn)
  439. char *rpn;    /* receive a pathname */
  440. {
  441.     register c;
  442.  
  443. #ifdef NFGVMIN
  444.     readline(1);
  445. #else
  446.     purgeline();
  447. #endif
  448.  
  449. et_tu:
  450.     Firstsec=TRUE;  Eofseen=FALSE;
  451.     sendline(Crcflg?WANTCRC:NAK);
  452.     Lleft=0;    /* Do read next time ... */
  453.     while ((c = wcgetsec(rpn, 100)) != 0) {
  454.         if (c == WCEOT) {
  455.             zperr( "Pathname fetch returned %d", c);
  456.             sendline(ACK);
  457.             Lleft=0;    /* Do read next time ... */
  458.             readline(1);
  459.             goto et_tu;
  460.         }
  461.         return ERROR;
  462.     }
  463.     sendline(ACK);
  464.     return OK;
  465. }
  466.  
  467. /*
  468.  * Adapted from CMODEM13.C, written by
  469.  * Jack M. Wierda and Roderick W. Hart
  470.  */
  471.  
  472. wcrx()
  473. {
  474.     register int sectnum, sectcurr;
  475.     register char sendchar;
  476.     register char *p;
  477.     int cblklen;            /* bytes to dump this block */
  478.  
  479.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  480.     sendchar=Crcflg?WANTCRC:NAK;
  481.  
  482.     for (;;) {
  483.         sendline(sendchar);    /* send it now, we're ready! */
  484.         Lleft=0;    /* Do read next time ... */
  485.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  486.         report(sectcurr);
  487.         if (sectcurr==(sectnum+1 &0377)) {
  488.             sectnum++;
  489.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  490.             if (putsec(secbuf, cblklen)==ERROR)
  491.                 return ERROR;
  492.             if ((Bytesleft-=cblklen) < 0)
  493.                 Bytesleft = 0;
  494.             sendchar=ACK;
  495.         }
  496.         else if (sectcurr==(sectnum&0377)) {
  497.             zperr( "Received dup Sector");
  498.             sendchar=ACK;
  499.         }
  500.         else if (sectcurr==WCEOT) {
  501.             if (closeit())
  502.                 return ERROR;
  503.             sendline(ACK);
  504.             Lleft=0;    /* Do read next time ... */
  505.             return OK;
  506.         }
  507.         else if (sectcurr==ERROR)
  508.             return ERROR;
  509.         else {
  510.             zperr( "Sync Error");
  511.             return ERROR;
  512.         }
  513.     }
  514. }
  515.  
  516. /*
  517.  * Wcgetsec fetches a Ward Christensen type sector.
  518.  * Returns sector number encountered or ERROR if valid sector not received,
  519.  * or CAN CAN received
  520.  * or WCEOT if eot sector
  521.  * time is timeout for first char, set to 4 seconds thereafter
  522.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  523.  *    (Caller must do that when he is good and ready to get next sector)
  524.  */
  525.  
  526. wcgetsec(rxbuf, maxtime)
  527. char *rxbuf;
  528. int maxtime;
  529. {
  530.     register checksum, wcj, firstch;
  531.     register unsigned short oldcrc;
  532.     register char *p;
  533.     int sectcurr;
  534.  
  535.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  536.  
  537.         if ((firstch=readline(maxtime))==STX) {
  538.             Blklen=1024; goto get2;
  539.         }
  540.         if (firstch==SOH) {
  541.             Blklen=128;
  542. get2:
  543.             sectcurr=readline(1);
  544.             if ((sectcurr+(oldcrc=readline(1)))==0377) {
  545.                 oldcrc=checksum=0;
  546.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  547.                     if ((firstch=readline(1)) < 0)
  548.                         goto bilge;
  549.                     oldcrc=updcrc(firstch, oldcrc);
  550.                     checksum += (*p++ = firstch);
  551.                 }
  552.                 if ((firstch=readline(1)) < 0)
  553.                     goto bilge;
  554.                 if (Crcflg) {
  555.                     oldcrc=updcrc(firstch, oldcrc);
  556.                     if ((firstch=readline(1)) < 0)
  557.                         goto bilge;
  558.                     oldcrc=updcrc(firstch, oldcrc);
  559.                     if (oldcrc & 0xFFFF)
  560.                         zperr( "CRC");
  561.                     else {
  562.                         Firstsec=FALSE;
  563.                         return sectcurr;
  564.                     }
  565.                 }
  566.                 else if (((checksum-firstch)&0377)==0) {
  567.                     Firstsec=FALSE;
  568.                     return sectcurr;
  569.                 }
  570.                 else
  571.                     zperr( "Checksum");
  572.             }
  573.             else
  574.                 zperr("Sector number garbled");
  575.         }
  576.         /* make sure eot really is eot and not just mixmash */
  577. #ifdef NFGVMIN
  578.         else if (firstch==EOT && readline(1)==TIMEOUT)
  579.             return WCEOT;
  580. #else
  581.         else if (firstch==EOT && Lleft==0)
  582.             return WCEOT;
  583. #endif
  584.         else if (firstch==CAN) {
  585.             if (Lastrx==CAN) {
  586.                 zperr( "Sender CANcelled");
  587.                 return ERROR;
  588.             } else {
  589.                 Lastrx=CAN;
  590.                 continue;
  591.             }
  592.         }
  593.         else if (firstch==TIMEOUT) {
  594.             if (Firstsec)
  595.                 goto humbug;
  596. bilge:
  597.             zperr( "TIMEOUT");
  598.         }
  599.         else
  600.             zperr( "Got 0%o sector header", firstch);
  601.  
  602. humbug:
  603.         Lastrx=0;
  604.         while(readline(1)!=TIMEOUT)
  605.             ;
  606.         if (Firstsec) {
  607.             sendline(Crcflg?WANTCRC:NAK);
  608.             Lleft=0;    /* Do read next time ... */
  609.         } else {
  610.             maxtime=40; sendline(NAK);
  611.             Lleft=0;    /* Do read next time ... */
  612.         }
  613.     }
  614.     /* try to stop the bubble machine. */
  615.     canit();
  616.     return ERROR;
  617. }
  618.  
  619. #ifndef vax11c
  620. /*
  621.  * This version of readline is reasoably well suited for
  622.  * reading many characters.
  623.  *  (except, currently, for the Regulus version!)
  624.  *
  625.  * timeout is in tenths of seconds
  626.  */
  627. readline(timeout)
  628. int timeout;
  629. {
  630.     register n;
  631.     static char *cdq;    /* pointer for removing chars from linbuf */
  632.  
  633.     if (--Lleft >= 0) {
  634.         if (Verbose > 8) {
  635.             fprintf(stderr, "%02x ", *cdq&0377);
  636.         }
  637.         return (*cdq++ & 0377);
  638.     }
  639.     n = timeout/10;
  640.     if (n < 2)
  641.         n = 3;
  642.     if (Verbose > 5)
  643.         fprintf(stderr, "Calling read: alarm=%d  Readnum=%d ",
  644.           n, Readnum);
  645.     if (setjmp(tohere)) {
  646. #ifdef TIOCFLUSH
  647. /*        ioctl(iofd, TIOCFLUSH, 0); */
  648. #endif
  649.         Lleft = 0;
  650.         if (Verbose>1)
  651.             fprintf(stderr, "Readline:TIMEOUT\n");
  652.         return TIMEOUT;
  653.     }
  654.     signal(SIGALRM, alrm); alarm(n);
  655.     Lleft=read(iofd, cdq=linbuf, Readnum);
  656.     alarm(0);
  657.     if (Verbose > 5) {
  658.         fprintf(stderr, "Read returned %d bytes\n", Lleft);
  659.     }
  660.     if (Lleft < 1)
  661.         return TIMEOUT;
  662.     --Lleft;
  663.     if (Verbose > 8) {
  664.         fprintf(stderr, "%02x ", *cdq&0377);
  665.     }
  666.     return (*cdq++ & 0377);
  667. }
  668.  
  669.  
  670.  
  671. /*
  672.  * Purge the modem input queue of all characters
  673.  */
  674. purgeline()
  675. {
  676.     Lleft = 0;
  677. #ifdef USG
  678.     ioctl(iofd, TCFLSH, 0);
  679. #else
  680.     lseek(iofd, 0L, 2);
  681. #endif
  682. }
  683. #endif
  684.  
  685.  
  686. /*
  687.  * Process incoming file information header
  688.  */
  689. procheader(name)
  690. char *name;
  691. {
  692.     register char *openmode, *p, **pp;
  693.  
  694.     /* set default parameters and overrides */
  695.     openmode = "w";
  696.     Thisbinary = (!Rxascii) || Rxbinary;
  697.     if (Lzmanag)
  698.         zmanag = Lzmanag;
  699.  
  700.     /*
  701.      *  Process ZMODEM remote file management requests
  702.      */
  703.     if (!Rxbinary && zconv == ZCNL)    /* Remote ASCII override */
  704.         Thisbinary = 0;
  705.     if (zconv == ZCBIN)    /* Remote Binary override */
  706.         Thisbinary = TRUE;
  707.     else if (zmanag == ZMAPND)
  708.         openmode = "a";
  709.  
  710. #ifndef BIX
  711.     /* Check for existing file */
  712.     if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) {
  713.         fclose(fout);  return ERROR;
  714.     }
  715. #endif
  716.  
  717.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  718.  
  719.     p = name + 1 + strlen(name);
  720.     if (*p) {    /* file coming from Unix or DOS system */
  721.         sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  722. #ifndef vax11c
  723.         if (Filemode & UNIXFILE)
  724.             ++Thisbinary;
  725. #endif
  726.         if (Verbose) {
  727.             fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
  728.               name, Bytesleft, Modtime, Filemode);
  729.         }
  730.     }
  731.  
  732. #ifdef BIX
  733.     if ((fout=fopen("scratchpad", openmode)) == NULL)
  734.         return ERROR;
  735.     return OK;
  736. #else
  737.  
  738.     else {        /* File coming from CP/M system */
  739.         for (p=name; *p; ++p)        /* change / to _ */
  740.             if ( *p == '/')
  741.                 *p = '_';
  742.  
  743.         if ( *--p == '.')        /* zap trailing period */
  744.             *p = 0;
  745.     }
  746.  
  747. #ifndef vax11c
  748.     if (!Zmodem && MakeLCPathname && !IsAnyLower(name)
  749.       && !(Filemode&UNIXFILE))
  750.         uncaps(name);
  751. #endif
  752.     if (Topipe > 0) {
  753.         sprintf(Pathname, "%s %s", Progname+2, name);
  754.         if (Verbose)
  755.             fprintf(stderr,  "Topipe: %s %s\n",
  756.               Pathname, Thisbinary?"BIN":"ASCII");
  757. #ifndef vax11c
  758.         if ((fout=popen(Pathname, "w")) == NULL)
  759.             return ERROR;
  760. #endif
  761.     } else {
  762.         strcpy(Pathname, name);
  763.         if (Verbose) {
  764.             fprintf(stderr,  "Receiving %s %s %s\n",
  765.               name, Thisbinary?"BIN":"ASCII", openmode);
  766.         }
  767.         checkpath(name);
  768.         if (Nflag)
  769.             name = "/dev/null";
  770. #ifndef vax11c
  771. #ifdef OMEN
  772.         if (name[0] == '!' || name[0] == '|') {
  773.             if ( !(fout = popen(name+1, "w"))) {
  774.                 return ERROR;
  775.             }
  776.             Topipe = -1;  return(OK);
  777.         }
  778. #endif
  779. #endif
  780. #ifdef MD
  781.         fout = fopen(name, openmode);
  782.         if ( !fout)
  783.             if (make_dirs(name))
  784.                 fout = fopen(name, openmode);
  785. #else
  786.         fout = fopen(name, openmode);
  787. #endif
  788.         if ( !fout)
  789.             return ERROR;
  790.     }
  791.     return OK;
  792. #endif /* BIX */
  793. }
  794.  
  795. #ifdef MD
  796. /*
  797.  *  Directory-creating routines from Public Domain TAR by John Gilmore
  798.  */
  799.  
  800. /*
  801.  * After a file/link/symlink/dir creation has failed, see if
  802.  * it's because some required directory was not present, and if
  803.  * so, create all required dirs.
  804.  */
  805. make_dirs(pathname)
  806. register char *pathname;
  807. {
  808.     register char *p;        /* Points into path */
  809.     int madeone = 0;        /* Did we do anything yet? */
  810.     int save_errno = errno;        /* Remember caller's errno */
  811.     char *strchr();
  812.  
  813.     if (errno != ENOENT)
  814.         return 0;        /* Not our problem */
  815.  
  816.     for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
  817.         /* Avoid mkdir of empty string, if leading or double '/' */
  818.         if (p == pathname || p[-1] == '/')
  819.             continue;
  820.         /* Avoid mkdir where last part of path is '.' */
  821.         if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  822.             continue;
  823.         *p = 0;                /* Truncate the path there */
  824.         if ( !mkdir(pathname, 0777)) {    /* Try to create it as a dir */
  825.             vfile("Made directory %s\n", pathname);
  826.             madeone++;        /* Remember if we made one */
  827.             *p = '/';
  828.             continue;
  829.         }
  830.         *p = '/';
  831.         if (errno == EEXIST)        /* Directory already exists */
  832.             continue;
  833.         /*
  834.          * Some other error in the mkdir.  We return to the caller.
  835.          */
  836.         break;
  837.     }
  838.     errno = save_errno;        /* Restore caller's errno */
  839.     return madeone;            /* Tell them to retry if we made one */
  840. }
  841.  
  842. #if (MD != 2)
  843. #define    TERM_SIGNAL(status)    ((status) & 0x7F)
  844. #define TERM_COREDUMP(status)    (((status) & 0x80) != 0)
  845. #define TERM_VALUE(status)    ((status) >> 8)
  846. /*
  847.  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  848.  */
  849. mkdir(dpath, dmode)
  850. char *dpath;
  851. int dmode;
  852. {
  853.     int cpid, status;
  854.     struct stat statbuf;
  855.  
  856.     if (stat(dpath,&statbuf) == 0) {
  857.         errno = EEXIST;        /* Stat worked, so it already exists */
  858.         return -1;
  859.     }
  860.  
  861.     /* If stat fails for a reason other than non-existence, return error */
  862.     if (errno != ENOENT) return -1; 
  863.  
  864.     switch (cpid = fork()) {
  865.  
  866.     case -1:            /* Error in fork() */
  867.         return(-1);        /* Errno is set already */
  868.  
  869.     case 0:                /* Child process */
  870.         /*
  871.          * Cheap hack to set mode of new directory.  Since this
  872.          * child process is going away anyway, we zap its umask.
  873.          * FIXME, this won't suffice to set SUID, SGID, etc. on this
  874.          * directory.  Does anybody care?
  875.          */
  876.         status = umask(0);    /* Get current umask */
  877.         status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
  878.         execl("/bin/mkdir", "mkdir", dpath, (char *)0);
  879.         _exit(-1);        /* Can't exec /bin/mkdir */
  880.     
  881.     default:            /* Parent process */
  882.         while (cpid != wait(&status)) ;    /* Wait for kid to finish */
  883.     }
  884.  
  885.     if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
  886.         errno = EIO;        /* We don't know why, but */
  887.         return -1;        /* /bin/mkdir failed */
  888.     }
  889.  
  890.     return 0;
  891. }
  892. #endif /* MD != 2 */
  893. #endif /* MD */
  894.  
  895. /*
  896.  * Putsec writes the n characters of buf to receive file fout.
  897.  *  If not in binary mode, carriage returns, and all characters
  898.  *  starting with CPMEOF are discarded.
  899.  */
  900. putsec(buf, n)
  901. char *buf;
  902. register n;
  903. {
  904.     register char *p;
  905.  
  906.     if (n == 0)
  907.         return OK;
  908.     if (Thisbinary) {
  909.         for (p=buf; --n>=0; )
  910.             putc( *p++, fout);
  911.     }
  912.     else {
  913.         if (Eofseen)
  914.             return OK;
  915.         for (p=buf; --n>=0; ++p ) {
  916.             if ( *p == '\r')
  917.                 continue;
  918.             if (*p == CPMEOF) {
  919.                 Eofseen=TRUE; return OK;
  920.             }
  921.             putc(*p ,fout);
  922.         }
  923.     }
  924.     return OK;
  925. }
  926.  
  927. #ifndef vax11c
  928. /*
  929.  *  Send a character to modem.  Small is beautiful.
  930.  */
  931. sendline(c)
  932. {
  933.     char d;
  934.  
  935.     d = c;
  936.     if (Verbose>6)
  937.         fprintf(stderr, "Sendline: %x\n", c);
  938.     write(1, &d, 1);
  939. }
  940.  
  941. flushmo() {}
  942. #endif
  943.  
  944.  
  945.  
  946.  
  947.  
  948. /* make string s lower case */
  949. uncaps(s)
  950. register char *s;
  951. {
  952.     for ( ; *s; ++s)
  953.         if (isupper(*s))
  954.             *s = tolower(*s);
  955. }
  956. /*
  957.  * IsAnyLower returns TRUE if string s has lower case letters.
  958.  */
  959. IsAnyLower(s)
  960. register char *s;
  961. {
  962.     for ( ; *s; ++s)
  963.         if (islower(*s))
  964.             return TRUE;
  965.     return FALSE;
  966. }
  967.  
  968. /*
  969.  * substr(string, token) searches for token in string s
  970.  * returns pointer to token within string if found, NULL otherwise
  971.  */
  972. char *
  973. substr(s, t)
  974. register char *s,*t;
  975. {
  976.     register char *ss,*tt;
  977.     /* search for first char of token */
  978.     for (ss=s; *s; s++)
  979.         if (*s == *t)
  980.             /* compare token with substring */
  981.             for (ss=s,tt=t; ;) {
  982.                 if (*tt == 0)
  983.                     return s;
  984.                 if (*ss++ != *tt++)
  985.                     break;
  986.             }
  987.     return NULL;
  988. }
  989.  
  990. /*
  991.  * Log an error
  992.  */
  993. /*VARARGS1*/
  994. zperr(s,p,u)
  995. char *s, *p, *u;
  996. {
  997.     if (Verbose <= 0)
  998.         return;
  999.     fprintf(stderr, "Retry %d: ", errors);
  1000.     fprintf(stderr, s, p, u);
  1001.     fprintf(stderr, "\n");
  1002. }
  1003.  
  1004. /* send cancel string to get the other end to shut up */
  1005. canit()
  1006. {
  1007.     static char canistr[] = {
  1008.      24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  1009.     };
  1010.  
  1011. #ifdef vax11c
  1012.     raw_wbuf(strlen(canistr), canistr);
  1013.     purgeline();
  1014. #else
  1015.     printf(canistr);
  1016.     Lleft=0;    /* Do read next time ... */
  1017.     fflush(stdout);
  1018. #endif
  1019. }
  1020.  
  1021.  
  1022. report(sct)
  1023. int sct;
  1024. {
  1025.     if (Verbose>1)
  1026.         fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
  1027. }
  1028.  
  1029. #ifndef vax11c
  1030. /*
  1031.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
  1032.  * If called as [-][dir/../]rzCOMMAND set the pipe flag
  1033.  * If called as rb use YMODEM protocol
  1034.  */
  1035. chkinvok(s)
  1036. char *s;
  1037. {
  1038.     register char *p;
  1039.  
  1040.     p = s;
  1041.     while (*p == '-')
  1042.         s = ++p;
  1043.     while (*p)
  1044.         if (*p++ == '/')
  1045.             s = p;
  1046.     if (*s == 'v') {
  1047.         Verbose=1; ++s;
  1048.     }
  1049.     Progname = s;
  1050.     if (s[0]=='r' && s[1]=='z')
  1051.         Batch = TRUE;
  1052.     if (s[0]=='r' && s[1]=='b')
  1053.         Batch = Nozmodem = TRUE;
  1054.     if (s[2] && s[0]=='r' && s[1]=='b')
  1055.         Topipe = 1;
  1056.     if (s[2] && s[0]=='r' && s[1]=='z')
  1057.         Topipe = 1;
  1058. }
  1059. #endif
  1060.  
  1061. /*
  1062.  * Totalitarian Communist pathname processing
  1063.  */
  1064. checkpath(name)
  1065. char *name;
  1066. {
  1067.     if (Restricted) {
  1068.         if (fopen(name, "r") != NULL) {
  1069.             canit();
  1070.             fprintf(stderr, "\r\nrz: %s exists\n", name);
  1071.             bibi(-1);
  1072.         }
  1073.         /* restrict pathnames to current tree or uucppublic */
  1074.         if ( substr(name, "../")
  1075.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  1076.             canit();
  1077.             fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
  1078.             bibi(-1);
  1079.         }
  1080.     }
  1081. }
  1082.  
  1083. /*
  1084.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  1085.  *  Handles ZSINIT frame
  1086.  *  Return ZFILE if Zmodem filename received, -1 on error,
  1087.  *   ZCOMPL if transaction finished,  else 0
  1088.  */
  1089. tryz()
  1090. {
  1091.     register c, n;
  1092.     register cmdzack1flg;
  1093.  
  1094.     if (Nozmodem)        /* Check for "rb" program name */
  1095.         return 0;
  1096.  
  1097.  
  1098.     for (n=Zmodem?15:5; --n>=0; ) {
  1099.         /* Set buffer length (0) and capability flags */
  1100. #ifdef SEGMENTS
  1101.         stohdr(SEGMENTS*1024L);
  1102. #else
  1103.         stohdr(0L);
  1104. #endif
  1105. #ifdef CANBREAK
  1106.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  1107. #else
  1108.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  1109. #endif
  1110.         if (Zctlesc)
  1111.             Txhdr[ZF0] |= TESCCTL;
  1112.         zshhdr(tryzhdrtype, Txhdr);
  1113.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  1114.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  1115. again:
  1116.         switch (zgethdr(Rxhdr, 0)) {
  1117.         case ZRQINIT:
  1118.             continue;
  1119.         case ZEOF:
  1120.             continue;
  1121.         case TIMEOUT:
  1122.             continue;
  1123.         case ZFILE:
  1124.             zconv = Rxhdr[ZF0];
  1125.             zmanag = Rxhdr[ZF1];
  1126.             ztrans = Rxhdr[ZF2];
  1127.             tryzhdrtype = ZRINIT;
  1128.             c = zrdata(secbuf, 1024);
  1129.             mode(3);
  1130.             if (c == GOTCRCW)
  1131.                 return ZFILE;
  1132.             zshhdr(ZNAK, Txhdr);
  1133.             goto again;
  1134.         case ZSINIT:
  1135.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  1136.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  1137.                 stohdr(1L);
  1138.                 zshhdr(ZACK, Txhdr);
  1139.                 goto again;
  1140.             }
  1141.             zshhdr(ZNAK, Txhdr);
  1142.             goto again;
  1143.         case ZFREECNT:
  1144.             stohdr(getfree());
  1145.             zshhdr(ZACK, Txhdr);
  1146.             goto again;
  1147.         case ZCOMMAND:
  1148. #ifdef vax11c
  1149.             return ERROR;
  1150. #else
  1151.             cmdzack1flg = Rxhdr[ZF0];
  1152.             if (zrdata(secbuf, 1024) == GOTCRCW) {
  1153.                 if (cmdzack1flg & ZCACK1)
  1154.                     stohdr(0L);
  1155.                 else
  1156.                     stohdr((long)sys2(secbuf));
  1157.                 purgeline();    /* dump impatient questions */
  1158.                 do {
  1159.                     zshhdr(ZCOMPL, Txhdr);
  1160.                 }
  1161.                 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  1162.                 ackbibi();
  1163.                 if (cmdzack1flg & ZCACK1)
  1164.                     exec2(secbuf);
  1165.                 return ZCOMPL;
  1166.             }
  1167.             zshhdr(ZNAK, Txhdr); goto again;
  1168. #endif
  1169.         case ZCOMPL:
  1170.             goto again;
  1171.         default:
  1172.             continue;
  1173.         case ZFIN:
  1174.             ackbibi(); return ZCOMPL;
  1175.         case ZCAN:
  1176.             return ERROR;
  1177.         }
  1178.     }
  1179.     return 0;
  1180. }
  1181.  
  1182. /*
  1183.  * Receive 1 or more files with ZMODEM protocol
  1184.  */
  1185. rzfiles()
  1186. {
  1187.     register c;
  1188.  
  1189.     for (;;) {
  1190.         switch (c = rzfile()) {
  1191.         case ZEOF:
  1192.         case ZSKIP:
  1193.             switch (tryz()) {
  1194.             case ZCOMPL:
  1195.                 return OK;
  1196.             default:
  1197.                 return ERROR;
  1198.             case ZFILE:
  1199.                 break;
  1200.             }
  1201.             continue;
  1202.         default:
  1203.             return c;
  1204.         case ERROR:
  1205.             return ERROR;
  1206.         }
  1207.     }
  1208. }
  1209.  
  1210. /*
  1211.  * Receive a file with ZMODEM protocol
  1212.  *  Assumes file name frame is in secbuf
  1213.  */
  1214. rzfile()
  1215. {
  1216.     register c, n;
  1217.     long rxbytes;
  1218.  
  1219.     Eofseen=FALSE;
  1220.     if (procheader(secbuf) == ERROR) {
  1221.         return (tryzhdrtype = ZSKIP);
  1222.     }
  1223.  
  1224.     n = 20; rxbytes = 0l;
  1225.  
  1226.     for (;;) {
  1227. #ifdef SEGMENTS
  1228.         chinseg = 0;
  1229. #endif
  1230.         stohdr(rxbytes);
  1231.         zshhdr(ZRPOS, Txhdr);
  1232. nxthdr:
  1233.         switch (c = zgethdr(Rxhdr, 0)) {
  1234.         default:
  1235.             vfile("rzfile: zgethdr returned %d", c);
  1236.             return ERROR;
  1237.         case ZNAK:
  1238.         case TIMEOUT:
  1239. #ifdef SEGMENTS
  1240.             putsec(secbuf, chinseg);
  1241.             chinseg = 0;
  1242. #endif
  1243.             if ( --n < 0) {
  1244.                 vfile("rzfile: zgethdr returned %d", c);
  1245.                 return ERROR;
  1246.             }
  1247.         case ZFILE:
  1248.             zrdata(secbuf, 1024);
  1249.             continue;
  1250.         case ZEOF:
  1251. #ifdef SEGMENTS
  1252.             putsec(secbuf, chinseg);
  1253.             chinseg = 0;
  1254. #endif
  1255.             if (rclhdr(Rxhdr) != rxbytes) {
  1256.                 /*
  1257.                  * Ignore eof if it's at wrong place - force
  1258.                  *  a timeout because the eof might have gone
  1259.                  *  out before we sent our zrpos.
  1260.                  */
  1261.                 errors = 0;  goto nxthdr;
  1262.             }
  1263.             if (closeit()) {
  1264.                 tryzhdrtype = ZFERR;
  1265.                 vfile("rzfile: closeit returned <> 0");
  1266.                 return ERROR;
  1267.             }
  1268.             vfile("rzfile: normal EOF");
  1269.             return c;
  1270.         case ERROR:    /* Too much garbage in header search error */
  1271. #ifdef SEGMENTS
  1272.             putsec(secbuf, chinseg);
  1273.             chinseg = 0;
  1274. #endif
  1275.             if ( --n < 0) {
  1276.                 vfile("rzfile: zgethdr returned %d", c);
  1277.                 return ERROR;
  1278.             }
  1279.             zmputs(Attn);
  1280.             continue;
  1281.         case ZSKIP:
  1282. #ifdef SEGMENTS
  1283.             putsec(secbuf, chinseg);
  1284.             chinseg = 0;
  1285. #endif
  1286.             closeit();
  1287.             vfile("rzfile: Sender SKIPPED file");
  1288.             return c;
  1289.         case ZDATA:
  1290.             if (rclhdr(Rxhdr) != rxbytes) {
  1291.                 if ( --n < 0) {
  1292.                     return ERROR;
  1293.                 }
  1294. #ifdef SEGMENTS
  1295.                 putsec(secbuf, chinseg);
  1296.                 chinseg = 0;
  1297. #endif
  1298.                 zmputs(Attn);  continue;
  1299.             }
  1300. moredata:
  1301.             if (Verbose>1)
  1302.                 fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1303.                   rxbytes, Crc32?" CRC-32":"");
  1304. #ifdef SEGMENTS
  1305.             if (chinseg >= (1024 * SEGMENTS)) {
  1306.                 putsec(secbuf, chinseg);
  1307.                 chinseg = 0;
  1308.             }
  1309.             switch (c = zrdata(secbuf+chinseg, 1024))
  1310. #else
  1311.             switch (c = zrdata(secbuf, 1024))
  1312. #endif
  1313.             {
  1314.             case ZCAN:
  1315. #ifdef SEGMENTS
  1316.                 putsec(secbuf, chinseg);
  1317.                 chinseg = 0;
  1318. #endif
  1319.                 vfile("rzfile: zgethdr returned %d", c);
  1320.                 return ERROR;
  1321.             case ERROR:    /* CRC error */
  1322. #ifdef SEGMENTS
  1323.                 putsec(secbuf, chinseg);
  1324.                 chinseg = 0;
  1325. #endif
  1326.                 if ( --n < 0) {
  1327.                     vfile("rzfile: zgethdr returned %d", c);
  1328.                     return ERROR;
  1329.                 }
  1330.                 zmputs(Attn);
  1331.                 continue;
  1332.             case TIMEOUT:
  1333. #ifdef SEGMENTS
  1334.                 putsec(secbuf, chinseg);
  1335.                 chinseg = 0;
  1336. #endif
  1337.                 if ( --n < 0) {
  1338.                     vfile("rzfile: zgethdr returned %d", c);
  1339.                     return ERROR;
  1340.                 }
  1341.                 continue;
  1342.             case GOTCRCW:
  1343.                 n = 20;
  1344. #ifdef SEGMENTS
  1345.                 chinseg += Rxcount;
  1346.                 putsec(secbuf, chinseg);
  1347.                 chinseg = 0;
  1348. #else
  1349.                 putsec(secbuf, Rxcount);
  1350. #endif
  1351.                 rxbytes += Rxcount;
  1352.                 stohdr(rxbytes);
  1353.                 zshhdr(ZACK, Txhdr);
  1354.                 sendline(XON);
  1355.                 goto nxthdr;
  1356.             case GOTCRCQ:
  1357.                 n = 20;
  1358. #ifdef SEGMENTS
  1359.                 chinseg += Rxcount;
  1360. #else
  1361.                 putsec(secbuf, Rxcount);
  1362. #endif
  1363.                 rxbytes += Rxcount;
  1364.                 stohdr(rxbytes);
  1365.                 zshhdr(ZACK, Txhdr);
  1366.                 goto moredata;
  1367.             case GOTCRCG:
  1368.                 n = 20;
  1369. #ifdef SEGMENTS
  1370.                 chinseg += Rxcount;
  1371. #else
  1372.                 putsec(secbuf, Rxcount);
  1373. #endif
  1374.                 rxbytes += Rxcount;
  1375.                 goto moredata;
  1376.             case GOTCRCE:
  1377.                 n = 20;
  1378. #ifdef SEGMENTS
  1379.                 chinseg += Rxcount;
  1380. #else
  1381.                 putsec(secbuf, Rxcount);
  1382. #endif
  1383.                 rxbytes += Rxcount;
  1384.                 goto nxthdr;
  1385.             }
  1386.         }
  1387.     }
  1388. }
  1389.  
  1390. /*
  1391.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  1392.  *   and \335 (break signal)
  1393.  */
  1394. zmputs(s)
  1395. char *s;
  1396. {
  1397.     register c;
  1398.  
  1399.     while (*s) {
  1400.         switch (c = *s++) {
  1401.         case '\336':
  1402.             sleep(1); continue;
  1403.         case '\335':
  1404.             sendbrk(); continue;
  1405.         default:
  1406.             sendline(c);
  1407.         }
  1408.     }
  1409. }
  1410.  
  1411. /*
  1412.  * Close the receive dataset, return OK or ERROR
  1413.  */
  1414. closeit()
  1415. {
  1416.     time_t time();
  1417.  
  1418. #ifndef vax11c
  1419.     if (Topipe) {
  1420.         if (pclose(fout)) {
  1421.             return ERROR;
  1422.         }
  1423.         return OK;
  1424.     }
  1425. #endif
  1426.     if (fclose(fout)==ERROR) {
  1427.         fprintf(stderr, "file close ERROR\n");
  1428.         return ERROR;
  1429.     }
  1430. #ifndef vax11c
  1431.     if (Modtime) {
  1432.         timep[0] = time(NULL);
  1433.         timep[1] = Modtime;
  1434.         utime(Pathname, timep);
  1435.     }
  1436. #endif
  1437.     if ((Filemode&S_IFMT) == S_IFREG)
  1438.         chmod(Pathname, (07777 & Filemode));
  1439.     return OK;
  1440. }
  1441.  
  1442. /*
  1443.  * Ack a ZFIN packet, let byegones be byegones
  1444.  */
  1445. ackbibi()
  1446. {
  1447.     register n;
  1448.  
  1449.     vfile("ackbibi:");
  1450.     Readnum = 1;
  1451.     stohdr(0L);
  1452.     for (n=3; --n>=0; ) {
  1453.         purgeline();
  1454.         zshhdr(ZFIN, Txhdr);
  1455.         switch (readline(100)) {
  1456.         case 'O':
  1457.             readline(1);    /* Discard 2nd 'O' */
  1458.             vfile("ackbibi complete");
  1459.             return;
  1460.         case RCDO:
  1461.             return;
  1462.         case TIMEOUT:
  1463.         default:
  1464.             break;
  1465.         }
  1466.     }
  1467. }
  1468.  
  1469.  
  1470.  
  1471. /*
  1472.  * Local console output simulation
  1473.  */
  1474. bttyout(c)
  1475. {
  1476.     if (Verbose || Fromcu)
  1477.         putc(c, stderr);
  1478. }
  1479.  
  1480. #ifndef vax11c
  1481. /*
  1482.  * Strip leading ! if present, do shell escape. 
  1483.  */
  1484. sys2(s)
  1485. register char *s;
  1486. {
  1487.     if (*s == '!')
  1488.         ++s;
  1489.     return system(s);
  1490. }
  1491. /*
  1492.  * Strip leading ! if present, do exec.
  1493.  */
  1494. exec2(s)
  1495. register char *s;
  1496. {
  1497.     if (*s == '!')
  1498.         ++s;
  1499.     mode(0);
  1500.     execl("/bin/sh", "sh", "-c", s);
  1501. }
  1502. #endif
  1503. /* End of rz.c */
  1504.